package com.chinairi.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinairi.common.config.JwtConfig;
import com.chinairi.common.utils.Md5Util;
import com.chinairi.common.utils.RedisUtil;
import com.chinairi.common.utils.UserSession;
import com.chinairi.mall.dao.SysMenuMapper;
import com.chinairi.mall.param.SysMenuQueryModel;
import com.chinairi.mall.dao.SysUserMapper;
import com.chinairi.mall.dao.UserCompanyTypeMapper;
import com.chinairi.mall.error.BusinessException;
import com.chinairi.mall.error.EmBusinessError;
import com.chinairi.mall.model.*;
import com.chinairi.mall.dao.SysUserLoginMapper;
import com.chinairi.mall.model.UserCompanyType;
import com.chinairi.mall.service.ISysUserLoginService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinairi.mall.service.modelobject.SysUserLoginMO;
import com.chinairi.mall.service.modelobject.UserInfoToRedisMO;
import com.chinairi.mall.util.AbstractEncryptUtil;
import com.chinairi.mall.util.EmailUtil;
import com.chinairi.mall.util.GaoDeMapUtil;
import com.chinairi.mall.util.RandomUtil;
import com.chinairi.sms.api.utils.SmsSendUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 用户账号信息表 服务实现类
 * </p>
 *
 * @author 董志涵
 * @since 2020-08-17
 */
@Service
public class SysUserLoginServiceImpl extends ServiceImpl<SysUserLoginMapper, SysUserLogin> implements ISysUserLoginService {
    @Autowired
    private SysUserLoginMapper sysUserLoginMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private JwtConfig jwtConfig;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private UserCompanyTypeMapper userCompanyTypeMapper;
    @Autowired
    private EmailUtil emailUtil;

    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private SysUserServiceImpl sysUserService;

    @Override
    public void insertSysUser(SysUserLogin sysUserLogin) {
        sysUserLoginMapper.insert(sysUserLogin);
    }

    @Override
    public SysUserLogin getSysUserByUserMail(String userMail) {
        return sysUserLoginMapper.getSysUserByUserMail(userMail);
    }

    @Override
    public SysUserLogin getSysUserByUserName(String userName) {
        return sysUserLoginMapper.getSysUserByUserName(userName);
    }


    @Override
    public SysUserLoginMO login(HttpServletResponse response, HttpServletRequest request) throws Exception {
        String userName = request.getHeader("userName");
        System.out.println("解密前密码：" + request.getHeader("password"));
        String passwordMd5 = AbstractEncryptUtil.decrypt(request.getHeader("password"));
//        String passwordMd5= Md5Util.stringMd5(request.getHeader("password"));
        SysUserLogin sysUserLogin = new SysUserLogin();

        if (userName.contains("@")) {
            sysUserLogin = sysUserLoginMapper.getSysUserByUserMail(userName);
        } else if (judgeContainsStr(userName)) {
            sysUserLogin = sysUserLoginMapper.getSysUserByUserName(userName);
        } else {
            SysUser sysUser = new SysUser();
            sysUser = sysUserMapper.getSysUserByPhoneNumber(userName);
            sysUserLogin = sysUserLoginMapper.getSysUserByUuid(sysUser.getUserId());
        }
        if (sysUserLogin == null) {
            throw new BusinessException(EmBusinessError.STUDENT_NOT_EXIST);
        } else if (sysUserLogin.getLoginNum().intValue() >= 5) {
            throw new BusinessException(EmBusinessError.STUDENT_LOGIN_TOO_MANY);
        } else if (!passwordMd5.equals(sysUserLogin.getLoginPwd())) {
            int loginNum = sysUserLogin.getLoginNum().intValue() + 1;
            sysUserLoginMapper.updateByUuid(sysUserLogin.getUserId(), loginNum);
            throw new BusinessException(EmBusinessError.STUDENT_LOGIN_FAIL, "密码错误，还可以尝试" + (5 - loginNum) + "次");
        } else {
            String last3Month = getLast3MonthString("yyyy-MM-dd");
            Date updatePasswordTime = sysUserLogin.getLoginPwdUptTime();
            if (compare(updatePasswordTime, last3Month)) {
                throw new BusinessException(EmBusinessError.Three_MONTH, sysUserLogin.getUserId());
            }
            String token = jwtConfig.getToken(sysUserLogin.getUserId());
            sysUserLoginMapper.updateErrorCount(sysUserLogin.getUserId());
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("userId", sysUserLogin.getUserId());
            userMap.put("userName", sysUserLogin.getLoginNm());
            userMap.put("loginNm", sysUserLogin.getDisplayNm());
            userMap.put("orgId", sysUserLogin.getOrgCode());
            redisUtil.hmset(token, userMap, 3600);

            SysUserLoginMO sysUserLoginMo = sysUserLoginMapper.getLoginInfo(sysUserLogin.getUserId());
            if (sysUserLoginMo.getUciDbid() != null) {
                List<UserCompanyType> result = userCompanyTypeMapper.getComTypeIntList(sysUserLoginMo.getUciDbid());
                sysUserLoginMo.setUserCompanyTypeList(result);
            }
            sysUserLoginMo.setToken(token);
            return sysUserLoginMo;
        }

    }

    /**
     * 少了一步加密
     *
     * @param request
     * @throws Exception
     */
    @Override
    public void changePassword(HttpServletRequest request) throws Exception {
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowTime = simpleDateFormat.format(now);
        String uuid = UserSession.getUserId();
        String decodePrePassword = AbstractEncryptUtil.decrypt(request.getHeader("prePassword"));

        SysUserLogin sysUserLogin = sysUserLoginMapper.selectById(uuid);
        if (!sysUserLogin.getLoginPwd().equals(decodePrePassword)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户原密码错误");
        }
        String decodePassword = AbstractEncryptUtil.decrypt(request.getHeader("password"));
        sysUserLoginMapper.changePasswordByUuid(decodePassword, uuid, nowTime);
    }

    /**
     * 错误，需要重新改正
     *
     * @param request
     * @throws Exception
     */
    @Override
    public void forceChangePassword(HttpServletRequest request) throws Exception {
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowTime = simpleDateFormat.format(now);
        String uuid = UserSession.getUserId();
        String decodePassword = AbstractEncryptUtil.decrypt(request.getHeader("password"));
        sysUserLoginMapper.changePasswordByUuid(decodePassword, uuid, nowTime);
    }

    /**
     * 该方法主要使用正则表达式来判断字符串中是否包含字母
     *
     * @param cardNum 待检验的原始卡号
     * @return 返回是否包含
     */
    public boolean judgeContainsStr(String cardNum) {
        String regex = ".*[a-zA-Z]+.*";
        Matcher m = Pattern.compile(regex).matcher(cardNum);
        return m.matches();
    }

    /**
     * 获取三个月前的今天
     *
     * @param format
     * @return
     */
    public static String getLast3MonthString(String format) {
        String dateString = "";
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.MONTH, -3);
            Date date = calendar.getTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            dateString = simpleDateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dateString;
    }

    /**
     * 比较两个时间大小
     *
     * @param a
     * @param time2
     * @return
     * @throws ParseException
     */
    public boolean compare(Date a, String time2) throws ParseException {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //将字符串形式的时间转化为Date类型的时间
//        Date a=sdf.parse(time1);
        Date b = sdf.parse(time2);
        //Date类的一个方法，如果a早于b返回true，否则返回false
        if (a.before(b)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 反转手机号查重验证，用于修改密码
     *
     * @param phoneNumber
     * @param request
     * @return
     */
    @Override
    public String checkPhoneNumberEx(String phoneNumber, HttpServletRequest request) {
        if (phoneNumber == null || "".equals(phoneNumber)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "未输入手机号");
        }
        int checkResult = sysUserMapper.checkPhone(UserSession.getUserId(), phoneNumber);
        if (checkResult == 0) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "手机号未绑定用户");
        }
        String phoneCodeMd5 = RandomUtil.smsCode();
        SmsSendUtil.send(null, "", UserSession.getLoginName(), phoneNumber, "SMS_190794369", new String[]{phoneCodeMd5});
        return Md5Util.stringMd5(phoneCodeMd5);
    }

    /**
     * 忘记密码,手机号码加密码
     *
     * @param phone
     * @param request
     * @throws Exception
     */
    @Override
    public void forgetPassword(String phone, HttpServletRequest request) throws Exception {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper
                .eq(StringUtils.isNotEmpty(phone), "USER_MOBILE", phone);
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        if (sysUser == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "无此手机号的用户");
        } else {
            Date now = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String nowTime = simpleDateFormat.format(now);
            String decodePassword = AbstractEncryptUtil.decrypt(request.getHeader("password"));
            sysUserLoginMapper.changePasswordByUuid(decodePassword, sysUser.getUserId(), nowTime);
            sysUserService.putRedis();
        }
    }

    /**
     * 邮箱绑定用户
     *
     * @param email
     * @param request
     * @return
     */
    @Override
    public String checkMail(String email, HttpServletRequest request) {
        if (email == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "未输入邮箱");
        }
        int checkResult = sysUserLoginMapper.checkEmail(UserSession.getUserId(), email);
        if (checkResult > 0) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "邮箱已绑定用户");
        }
        return emailUtil.getEmail(email, "用户绑定邮箱验证码", "用户绑定邮箱验证码");
    }

    /**
     * 用户邮箱绑定
     *
     * @param mail
     * @param request
     */
    @Override
    public void updateMail(String mail, HttpServletRequest request) {
        if (mail != null) {
            SysUserLogin sysUserLogin = sysUserLoginMapper.selectById(UserSession.getUserId());
            if (sysUserLogin == null) {
                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户不存在");
            }
            sysUserLogin.setLoginEmail(mail);
            sysUserLoginMapper.updateById(sysUserLogin);
            sysUserService.putRedis();
        }
    }

    /**
     * 根据现实时间更新用户账号表，将login num置0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCheck() {
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowTime = simpleDateFormat.format(now);
        sysUserLoginMapper.updateCheck(nowTime);
    }

    /**
     * 校验密码
     *
     * @param request
     * @return
     */
    @Override
    public boolean passwordCheck(HttpServletRequest request) throws Exception {
        String password = AbstractEncryptUtil.decrypt(request.getHeader("password"));
        QueryWrapper<SysUserLogin> wrapper = new QueryWrapper<>();
        wrapper
                .eq(StringUtils.isNotEmpty(UserSession.getUserId()), "USER_ID", UserSession.getUserId())
                .eq(StringUtils.isNotEmpty(password), "LOGIN_PWD", password);
        SysUserLogin sysUserLogin = sysUserLoginMapper.selectOne(wrapper);
        if (sysUserLogin == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户原密码不正确");
        } else {
            return true;
        }
    }

    @Override
    public List<SysMenu> listPCWebMenu(String menuId) {
        String userId = UserSession.getUserId();
        SysUserLogin sysUserLogin = sysUserLoginMapper.selectById(userId);
        if (sysUserLogin == null) {
            return new ArrayList<SysMenu>();
        }
        String accountType = sysUserLogin.getAccountType();
        List<SysMenu> menuList = null;
        SysMenuQueryModel sysMenuQueryModel = new SysMenuQueryModel();
        if ("9".equals(accountType)) {
            menuList = sysMenuMapper.listSysMenu(sysMenuQueryModel);
        } else {
            sysMenuQueryModel.setUserId(UserSession.getUserId());
            sysMenuQueryModel.setMenuId(menuId);
            menuList = sysMenuMapper.listSysMenu(sysMenuQueryModel);

        }
        if (menuList == null || menuList.isEmpty()) {
            return new ArrayList<>();
        }
        getChildList(menuList, sysMenuQueryModel);
        return menuList;
    }

    private List<SysMenu> getChildList(List<SysMenu> sysMenuList, SysMenuQueryModel sysMenuQueryModel) {
        List<SysMenu> menuChildList = null;
        for (SysMenu sysMenu : sysMenuList) {
            String menuType = sysMenu.getMenuType();
            if ("1".equals(menuType)) {
                sysMenuQueryModel.setMenuId(sysMenu.getMenuId());
                menuChildList = sysMenuMapper.listSysMenu(sysMenuQueryModel);
                if (menuChildList == null || menuChildList.isEmpty()) {
                    menuChildList = new ArrayList<>();
                }
                sysMenu.setChildren(menuChildList);
            }
        }
        if (menuChildList != null && menuChildList.size() > 0) {
            return getChildList(menuChildList, sysMenuQueryModel);
        }
        return menuChildList;
    }

    public void setAreaMapToRedis() {
        redisUtil.del("areaMap");
        Map<String, Object> areaMap = new HashMap<>(1);
        areaMap.put("areaMap", GaoDeMapUtil.setResponseToRedis());
        redisUtil.hmset("areaMap", areaMap, 86500);
    }

    @Override
    public Map<Object, Object> getAreaMapFromRedis() {
        Map<Object, Object> areaMapResult = redisUtil.hmget("areaMap");
        if (!redisUtil.hasKey("areaMap") || areaMapResult.size() == 0) {
            setAreaMapToRedis();
        }
        return redisUtil.hmget("areaMap");
    }
}
